#define GR_VER "1.0"

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include <SDL.h>
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
#ifndef FILENAME_MAX
#define FILENAME_MAX 255
#endif
#define NAMELEN 256
#include "crypto.h"
#include "texts.h"
#include "sprites.h"
#define crc32 stbiw__crc32
uint32_t stbiw__crc32(void *buffer, int len);

#define FG 0xffcb7e88
#define BG 0xffa2323e

/* widgets.c */
extern uint32_t *unicodes, numunicodes;
extern uint8_t *glyphs;
extern int scrpos, scrbtn, scrcur, scrtot, scrdel;
void resize(uint32_t *dst, int x, int y, int w, int h, int p, uint32_t *src, int sw, int sh, int sp);
int text2(int cx, int cy, int cw, int ch, int p, uint32_t *d, int x, int y, uint32_t color, char *str);
int text(int x, int y, uint32_t color, char *str);
int textlen(char *str);
void box(int x, int y, int w, int h, uint32_t color);
void rect(int x, int y, int w, int h, uint32_t color1, uint32_t color2);
void txtfld(int x, int y, int w, int h, char *str);
void button(int x, int y, int w, int h, int pressed, char *str);
void selbox(int x, int y, int w, int h, int pressed, char *str);
void chkbox(int x, int y, int checked, char *str);
int hscroll(int x, int y, int h, int cur, int tot, int pressed);

/* fileop.c */
typedef int (*filecb_t)(char *fn);
extern char fn[PATH_MAX + FILENAME_MAX + 1];
extern int pathlen;
int fileknown(uint8_t *buf);
int fileasset(int id, char *name, uint8_t *buf, uint64_t size);
void filemkdir(char *fn);
void *fileopen(char *fn, uint64_t *size);
uint64_t fileread(void *f, void *buf, uint64_t size);
uint64_t filewrite(void *f, void *buf, uint64_t size);
void fileseek(void *f, uint64_t offs);
void fileclose(void *f);
int fileexists(char *fn);
uint8_t* getfile(char *fn, uint64_t *size);
int putfile(char *fn, uint8_t *buf1, uint64_t size1, uint8_t *buf2, uint64_t size2, uint8_t *buf3, uint64_t size3);
void opendialog(int msg, int dir);
void savedialog(char *path, char *name, uint8_t *buf, uint64_t size);
int find(char *path, int subdirs, filecb_t filecb);
uint64_t du(char *path);
uint64_t dn(char *path);

/* elfpe.c */
typedef struct {
    char name[8];
    uint64_t offs;
    uint64_t size;
} section_t;
extern section_t sections[64];
int elfpe_detect(char *fn);
int elfpe_getsections(char *fn, int list);

/* models.c */
extern int nummodels;
void models_free(void);
void models_ctrl(void);
void models_view(void);

/* maps.c */
typedef struct {
    int sprite, x, y;
} map_sprite_t;
typedef struct {
    int id, tid, tw, th, w, h, l, *data, numspr;
    char name[NAMELEN];
    map_sprite_t *spr;
} map_t;
extern int nummaps, mapnw, mapzoom;
int map_add(int id, char *name, int tid, int tw, int th, int w, int h, int l);
int *map_add_under(int map);
int *map_add_above(int map);
int *map_data(int map, int l);
int map_sprite(int map, int sprite, int x, int y);
void map_tile(int sheet, int x, int y, int w, int h, int dx, int dy);
void map_shadow(uint32_t color, int w, int h, int dx, int dy);
void maps_free(void);
void maps_ctrl(void);
void maps_view(void);

/* audio.c */
extern int numsfx, numbgm;
int audio_detect(uint8_t *buf);
uint8_t *audio_decode(uint8_t *buf, uint64_t size, int *len);
int audio_addsfx(int id, char *name, uint8_t *buf, uint32_t size);
int audio_addbgm(int id, char *name, uint8_t *buf, uint32_t size);
void audio_load(int sfx);
void audio_play(int sfx);
void audio_stop();
void audio_free(void);
void audio_ctrl(void);
void audio_view(void);

/* videos.c */
extern int numvideos;
void videos_free(void);
void videos_ctrl(void);
void videos_view(void);

/* texts.c */
typedef struct {
    int id;
    char *value[128];
} text_t;
extern text_t *texts;
extern int numcol, numrow, curcol;
int csv2mem(char *csv, int len);
char *mem2csv(int *size);
int base64_decode(char *s, uint8_t *out, int len);
uint64_t gethex(char *str, int num);
char *getvalue(char *json, int *value);
char *getstr(char *json, char *str, int maxlen);
char *newstr(char **jsonptr);
char *shiftjis2utf8(char *json, char *str, int maxlen);
char *toutf8(char *str, uint32_t u);
int validutf8(char *str);
int texts_addrow(int id);
int texts_getcol(char *str);
void texts_free(void);
void texts_ctrl(void);
void texts_view(void);

/* main.c */
enum { TAB_INFO, TAB_SPRITES, TAB_MODELS, TAB_MAPS, TAB_SFX, TAB_BGM, TAB_VIDEOS, TAB_TEXTS, TAB_CHEATS };
extern SDL_Renderer *renderer;
extern SDL_Event event;
extern SDL_Rect fields[64], sprrect, maprect;
extern SDL_Texture *screen, *sprite, *map;
extern int crop_x, crop_y, crop_w, crop_h;
extern int screen_w, screen_h, screen_p, mx, my, refresh, loaded, tab, field, pressedfield;
extern uint32_t ticks, *screen_d;
extern char **lang, verbose, decrypt, quit;
void debug(char *fmt, ...);
void status(int msg, uint64_t cur, uint64_t tot);
void msgbox(int error, int msg, char *param);
void refreshtabs(void);

/* engines.c */
void engine_map(map_t *map);
void engine_translate(void);
void engine_free(void);
void engine_stop(void);
void engine_init(char *fn);
void engine_view_ram(void);
void engine_keyinput_ctrl(void);
void engine_keyinput_view(void);
void engine_info_ctrl(void);
void engine_info_view(void);

typedef int (*engine_detect_t)(char *path, uint8_t *buf, uint64_t size);
typedef void (*engine_load_t)(char *path, int isdir);
typedef void (*engine_unload_t)(void);
typedef void (*engine_decrypt_t)(char *path, int isdir);
typedef void (*engine_drawmap_t)(map_t *map);
typedef void (*engine_translate_t)(char *path);
typedef struct {
    char *name, *mod;
    engine_detect_t detect;
    engine_load_t load;
    engine_unload_t unload;
    engine_decrypt_t decrypt;
    engine_drawmap_t drawmap;
    engine_translate_t translate;
} engine_module_t;
extern engine_module_t engine_modules[128];
extern int nummod;

/* available features for the detected game */
#define EF_STOP       -1
#define EF_NOOP        0
#define EF_LOAD        1
#define EF_DECRYPT     2
#define EF_SPRITES     4
#define EF_MODELS      8
#define EF_MAPS       16
#define EF_SFX        32
#define EF_BGM        64
#define EF_VIDEOS    128
#define EF_TEXTS     256
#define EF_CHEATS    512
#define EF_SCANSPR  0x1000
#define EF_BACKUP   0x2000
#define EF_CONVERT  0x4000
#define EF_NOMEM    0x10000
extern uint64_t engine_ram;
extern int engine_features, engine_backup, engine_convert, engine_keylen;
extern char engine_game[256];
extern uint8_t engine_key[256];

void engine_module(char *name, char *mod,
    engine_detect_t detect,
    engine_load_t load,
    engine_unload_t unload,
    engine_decrypt_t decrypt,
    engine_drawmap_t drawmap,
    engine_translate_t translate
);
#define ENGINE_MODULE(a, b) void __attribute__((constructor)) a ## _init(void) { \
    engine_module(b, #a, &a ## _detect, &a ## _load, &a ## _unload, &a ## _decrypt, &a ## _drawmap, &a ## _translate); }
